#pragma once

#include <vex/iterable/range_tags.h>
#include <vex/iterable/range_traits.h>
#include <boost/utility/enable_if.hpp>
#include <type_traits>

namespace vex {
    namespace iterable {

        /// marker class to identify duck-typed iterable value types
        class range_marker {
        protected:
            range_marker() {}
            ~range_marker() {}
        };

        /// Facade to derive from when defining a custom iterable. By convention,
        /// all ranges are supposed to derive from range_base
        template <
            class TCategory,
            class TRef,
            class TBase = range_marker
        >
        class range_base : public TBase {
        public:
            typedef TCategory category;
            typedef TRef reference;
        protected:
            ~range_base() {}
        };

        /// meta function to identify whether the type T is a iterable. true_type if
        /// range_marker is a base class, false_type otherwise
        template< class T >
        struct is_range : public std::is_base_of<range_marker, typename std::decay<T>::type> {};

        template<class T, class TResult> struct lazy_enable_if_range : public boost::lazy_enable_if_c<
            is_range<T>::value,
            TResult
        > {};

        template<class T, class TResult> struct lazy_disable_if_range : public boost::lazy_disable_if_c<
            is_range<T>::value,
            TResult
        > {};
    }
}